﻿using System;
using System.Collections.Generic;
using System.Text;

using System.Collections;
using System.Runtime.InteropServices;

using SuperMapLib;

namespace JR_RouteAlarm
{
    class Route : IRoute
    {
        /*定数*/
        public const string FEATURE_CD = Utility.FEATURE;
        public const string DAIBUN_CD = Utility.DAIBUN;
        public const string TSUUSHO_CD = Utility.TSUUSHO;

        #region IRoute メンバ

        private string feature = String.Empty;
        public string Feature
        {
            get
            {
                return feature;
            }
            set
            {
                feature = value;
            }
        }

        private string daibun = String.Empty;
        public string Daibun
        {
            get
            {
                return daibun;
            }
            set
            {
                daibun = value;
            }
        }

        private string tsuusho = String.Empty;
        public string Tsuusho
        {
            get
            {
                return tsuusho;
            }
            set
            {
                tsuusho = value;
            }
        }

        private void MakeBufferForPart(soGeoLine objLine)
        {
            soGeoLine[] objSideLines = new soGeoLine[Utility.MAX_ROUTE_PART_COUNT];
            soGeoPoint[] objTerminalPoints = new soGeoPoint[2];
            soPoints validPoints = null;
            double lineLen = 0D;

            /*一時変数*/
            soGeoRegion objRegionTmp = null;
            soGeoLine objLineTmp = null;
            soGeoPoint objPointTmp = null;
            soPoints tmpPoints = null;
            
            /*COMを解放するため、預かる*/
            ArrayList arrComObjects = new ArrayList();

            objRegionTmp = objLine.Buffer(Utility.BUFFER_ALARM_DISTANCE, Utility.BUFFER_ALARM_SMOOTH);
            objLineTmp = objRegionTmp.ConvertToLine();
            tmpPoints = objLineTmp.GetPartAt(1);

            lineLen = objLine.Length;
            objTerminalPoints[0] = new soGeoPoint();
            objTerminalPoints[1] = new soGeoPoint();
            arrComObjects.Add(objTerminalPoints[0]);
            arrComObjects.Add(objTerminalPoints[1]);
            objTerminalPoints[0].x = objLine.FindPointOnLineByDistance(0).x;
            objTerminalPoints[0].y = objLine.FindPointOnLineByDistance(0).y;
            objTerminalPoints[1].x = objLine.FindPointOnLineByDistance(lineLen).x;
            objTerminalPoints[1].y = objLine.FindPointOnLineByDistance(lineLen).y;

            objPointTmp = new soGeoPoint();
            validPoints = new soPoints();
            for (int i = 1; i < tmpPoints.Count; i++)
            {
                objPointTmp.x = tmpPoints[i].x;
                objPointTmp.y = tmpPoints[i].y;
                if (Math.Abs(objPointTmp.DistanceTo(objTerminalPoints[0] as soGeometry)
                        - Utility.BUFFER_ALARM_DISTANCE) < Utility.PRECISION
                    || Math.Abs(objPointTmp.DistanceTo(objTerminalPoints[1] as soGeometry)
                        - Utility.BUFFER_ALARM_DISTANCE) < Utility.PRECISION)
                {
                    validPoints.Add(tmpPoints[i]);
                }
            }

            for (int i = 1; i < validPoints.Count; i++)
            {
                objSideLines[i - 1] = new soGeoLine();
                objSideLines[i] = new soGeoLine();
                arrComObjects.Add(objSideLines[i - 1]);

                if (objLineTmp.Split(validPoints[i], objSideLines[i - 1], objSideLines[i]))
                {
                    objLineTmp = objSideLines[i];
                }
            }
            arrComObjects.Add(objSideLines[validPoints.Count - 1]);

            tmpPoints.RemoveAll();
            for (int i = 1; i < validPoints.Count; i++)
            {
                if (Math.Abs(objSideLines[i].Length - lineLen) < Utility.PRECISION)
                {
                    tmpPoints.Add(objSideLines[i].FindPointOnLineByDistance(0));
                    tmpPoints.Add(objSideLines[i].FindPointOnLineByDistance(lineLen));
                }
                if (tmpPoints.Count == 4)
                {
                    tmpPoints.Add(tmpPoints[1]);
                    break;
                }
            }

            objLineTmp.SetEmpty();
            objLineTmp.AddPart(tmpPoints);
            Utility.routeLnWithBfr[objLine] = objLineTmp.ConvertToRegion();

            Marshal.ReleaseComObject(objLineTmp);
            objLineTmp = null;
            Marshal.ReleaseComObject(validPoints);
            validPoints = null;
            Marshal.ReleaseComObject(tmpPoints);
            tmpPoints = null;
            for (int i = 0; i < arrComObjects.Count; i++)
            {
                Marshal.ReleaseComObject(arrComObjects[i]);
                arrComObjects[i] = null;
            }
            Marshal.ReleaseComObject(objPointTmp);
            objPointTmp = null;
            Marshal.ReleaseComObject(objRegionTmp);
            objRegionTmp = null;
        }

        public void MakePartsForRoute(soDatasetVector objVector, soRecordset objRS)
        {
            soRecordset objSubRs = null;

            feature = objRS.GetFieldValue(FEATURE_CD).ToString();
            daibun = objRS.GetFieldValue(DAIBUN_CD).ToString();
            tsuusho = objRS.GetFieldValue(TSUUSHO_CD).ToString();

            objSubRs = objVector.Query(
                FEATURE_CD + " = '" + feature + "' and " +
                DAIBUN_CD + " = '" + daibun + "' and " +
                TSUUSHO_CD + " = '" + tsuusho + "'",
                true, null, "");

            if (objSubRs != null && !(objSubRs.IsBOF() && objSubRs.IsEOF()))
            {
                if (!objSubRs.IsBOF())
                {
                    objSubRs.MoveFirst();
                }

                ArrayList listLine = new ArrayList();
                for (int i = 0; !objSubRs.IsEOF(); objSubRs.MoveNext(), i++)
                {
                    listLine.Add(objSubRs.GetGeometry() as soGeoLine);
                    MakeBufferForPart(listLine[i] as soGeoLine);
                    if (Utility.routeLnWithBfr[listLine[i]] == null)
                    {
                        Utility.routeLnWithBfr.Remove(listLine[i]);
                        listLine.RemoveAt(i);
                        i--;
                    }
                }
                Utility.routeFtrWithLn[new String[] { feature, daibun, tsuusho }] = listLine;

                Marshal.ReleaseComObject(objSubRs);
                objSubRs = null;
            }
        }

        #endregion
    }
}
